package com.yuzhihao.writejvm.constant;

import com.yuzhihao.writejvm.clazz.ClassInfo;
import com.yuzhihao.writejvm.format.ClassFormatEnum;
import com.yuzhihao.writejvm.format.PrintFormat;
import com.yuzhihao.writejvm.read.Parse;
import com.yuzhihao.writejvm.read.ReadClassFileFatory;
import lombok.Data;
import lombok.extern.log4j.Log4j2;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 小版本
 *
 * @author yzh
 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4">查看</a>
 * @since 2021年11月29日19:14:35
 */
@Data
@Log4j2
public class ConstantPool implements Parse {

    private ClassFormatEnum cfe_cpc = ClassFormatEnum.constant_pool_count;

    private ClassFormatEnum cfe_c = ClassFormatEnum.cps;

    protected String name;

    protected int tag;

    private int count;

    public Map<String, ConstantPool> pools = new TreeMap<>(Comparator.comparingInt(Integer::parseInt));

    public ConstantPool() {
    }

    public ConstantPool(Map<String, ConstantPool> pools) {
        this.pools = pools;
    }

    @Override
    public void parse(DataInputStream dis, ClassInfo ci) {
        try {
            this.count = Parse.byteToInt(cfe_cpc.getB(), dis);

            int i = 1;
            while (i < count) {
                String key = String.valueOf(i);
                byte b = dis.readByte();
                ConstantPool cp = ReadClassFileFatory.constant_pool_instance(b, pools);
                if (Objects.nonNull(cp)) {
                    cp.setTag(b);
                    cp.parse(dis, ci);
                    pools.put(key, cp);
                    //如果存在Long和Double类型的数据，索引需要加1，n+1被视为不可用索引
                    if(cp instanceof ConstantDoubleInfo || cp instanceof ConstantLongInfo){
                        i ++;
                    }
                }
                i++;
            }
            //因为有些常量是在toString方法里面实现的，所以需要先调用一下toString方法。
            pools.values().forEach(ConstantPool::print);
        } catch (IOException e) {
            log.error(e.getMessage());
        }

        this.out(ci);
    }

    public void out(ClassInfo ci) {
        ci.setConstant_pool_count(count);
        ci.setCp_info(this);
    }

    public String print(){
        return "";
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Constant Pool Count：").append(this.count).append(System.lineSeparator());
        builder.append("Constant Pool：").append(System.lineSeparator());

        List<String> collect = pools.keySet().stream().sorted(Comparator.comparingInt(Integer::parseInt)).collect(Collectors.toList());
        collect.forEach((key) -> {
            ConstantPool value = pools.get(key);
            //#1 = Methodref          #6.#26         // java/lang/Object."<init>":()V
            StringBuilder der = new StringBuilder();
            der.append(PrintFormat.HASHTAG).append(key).append(PrintFormat.EQUAL).append(value.name);
            while (der.length() <= 25) {
                der.append(PrintFormat.EMPTY);
            }
            builder.append(PrintFormat.EMPTY).append(der).append(value.print()).append(System.lineSeparator());
        });

        return builder.toString();
    }

    public String getConstant() {
        return "";
    }
}
